package com.a0soft.gphone.aTruffleHog.di;
/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Sam Lu <ysl.sam.lu (at) gmail.com>
 *
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.a0soft.gphone.aTruffleHog.util.CONSTS;
import com.a0soft.gphone.aTruffleHog.util.MiscUtil;
import com.a0soft.gphone.aTruffleHog.util.aDebug;
import com.a0soft.gphone.aTruffleHog.util.aSystemProperties;

import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;

class SysInfo extends BaseInfo {    
	private static final String LOG_TAG = SysInfo.class.getSimpleName();
	
	static void
    Build(DeviceInfo di)
    {
    	di.Put(DeviceInfoKey.K.ST_BOARD, Build.BOARD);
    	PutSysPropStr(di, DeviceInfoKey.K.ST_BOOTLOADER, "BOOTLOADER", "ro.bootloader"); //API 8
    	di.Put(DeviceInfoKey.K.ST_BRAND, Build.BRAND);
    	di.Put(DeviceInfoKey.K.ST_DEVICE, Build.DEVICE);
    	di.Put(DeviceInfoKey.K.ST_DISPLAY, Build.DISPLAY);
    	di.Put(DeviceInfoKey.K.ST_FINGERPRINT, Build.FINGERPRINT);
    	PutSysPropStr(di, DeviceInfoKey.K.ST_HARDWARE, "HARDWARE", "ro.hardware"); //API 8
    	di.Put(DeviceInfoKey.K.ST_HOST, Build.HOST);
    	di.Put(DeviceInfoKey.K.ST_ID, Build.ID);
    	di.Put(DeviceInfoKey.K.ST_MID, GetMID());
    	di.Put(DeviceInfoKey.K.ST_MANUFACTURE, Build.MANUFACTURER);
    	di.Put(DeviceInfoKey.K.ST_MODEL, Build.MODEL);
    	di.Put(DeviceInfoKey.K.ST_PRODUCT, Build.PRODUCT);
    	PutSysPropStr(di, DeviceInfoKey.K.ST_RADIO, "RADIO", "gsm.version.baseband"); //API 8
		// don't get Build.SERIAL, it's device ID, will have privacy issue
    	//PutStr(di, DeviceInfoKey.K.ST_SERIAL, cls, "SERIAL", "ro.serialno"); //API 9
    	di.Put(DeviceInfoKey.K.ST_TAGS, Build.TAGS);
    	di.Put(DeviceInfoKey.K.ST_TIME, Build.TIME);
    	di.Put(DeviceInfoKey.K.ST_TYPE, Build.TYPE);
    	di.Put(DeviceInfoKey.K.ST_USER, Build.USER);
    	
    	di.Put(DeviceInfoKey.K.ST_CODENAME, Build.VERSION.CODENAME);
    	di.Put(DeviceInfoKey.K.ST_INCREMENTAL, Build.VERSION.INCREMENTAL);
    	di.Put(DeviceInfoKey.K.ST_RELEASE, Build.VERSION.RELEASE);
    	di.Put(DeviceInfoKey.K.ST_SDK_INT, Build.VERSION.SDK_INT);

        di.Put(DeviceInfoKey.K.ST_LINUX_VERSION, GetFormattedKernelVersion());
        di.Put(DeviceInfoKey.K.ST_VM_VERSION, aSystemProperties.GetJavaSysProp("java.vm.version"));

        di.Put(DeviceInfoKey.K.ST_ROOTED, IsRootDevice());
        
        //refer to http://forum.xda-developers.com/showthread.php?t=1035082
        di.Put(DeviceInfoKey.K.ST_ROM_NAME, aSystemProperties.Get("ro.stats.romname", CONSTS.UNAVAILABLE));
        di.Put(DeviceInfoKey.K.ST_ROM_DEVNAME, aSystemProperties.Get("ro.stats.devname", CONSTS.UNAVAILABLE));
        di.Put(DeviceInfoKey.K.ST_ROM_VERSION, aSystemProperties.Get("ro.stats.romversion", CONSTS.UNAVAILABLE));
        
        _BuildSysFeatures(di);
        
        Configuration cfg = Resources.getSystem().getConfiguration();
        di.Put(DeviceInfoKey.K.ST_TOUCH_SCREEN, cfg.touchscreen);
        di.Put(DeviceInfoKey.K.ST_KEYBOARD, cfg.keyboard);
        di.Put(DeviceInfoKey.K.ST_NAVIGATION, cfg.navigation);
        
    }

	private static void
    _BuildSysFeatures(DeviceInfo di)
    {
        Context ctx = MiscUtil.GetAppContext();
        PackageManager pm = ctx.getPackageManager();
        
        FeatureInfo[] features = pm.getSystemAvailableFeatures();
        ArrayList<String> strFeatures = new ArrayList<String>(features.length);
        
        int i = 0;
        for (FeatureInfo feature: features) {
            if (aDebug.ENABLED) {
                aDebug.d(LOG_TAG, i + ": name=" + feature.name + ",reqGlEsVersion=" + feature.reqGlEsVersion);
                ++i;
            }
            
            if (feature.name != null) {
                strFeatures.add(feature.name);
            }
            else {
                di.Put(DeviceInfoKey.K.ST_GLES_VERSION, feature.reqGlEsVersion);
            }
        }
        di.Put(DeviceInfoKey.K.ST_FEATURES, strFeatures);
    }
	
	/*
    manufacture:HTC$
    device:bravo$
    model:HTC HD2$
    
    manufacture:unknown$
    device:leo$
    model:HTC HD2$
    
    manufacture:HTC$
    device:bravo$
    model:HTC Desire$
    
    manufacture:HTC$
    device:pyramid$
    model:HTC Sensation 4G$
    
    manufacture:HTC$
    device:pyramid$
    model:HTC Sensation Z710e$
    
    manufacture:HTC$
    device:pyramid$
    model:HTC Sensation Z710e$
    
    manufacture:motorola$
    device:umts_milestone2$
    model:MotoA953$    
	*/
	static String
	GetMID()
	{
		String strManufacture = Build.MANUFACTURER;
		String strModel = Build.MODEL;
		
		if (strModel == null)
			strModel = "";
		strModel = strModel.toLowerCase().trim();
		
		if (strManufacture == null)
			return strModel;
		strManufacture = strManufacture.toLowerCase().trim();
		
		if (strModel.startsWith(strManufacture))
			return strModel;
		else
			return strManufacture + "-" + strModel;
	}
	
	//refer to from 2.3, packages/apps/Settings/src/com/android/settings/DeviceInfoSettings.java
	static String 
	GetFormattedKernelVersion() 
	{
        String procVersionStr;

        try {
            BufferedReader reader = new BufferedReader(new FileReader("/proc/version"), 256);
            try {
                procVersionStr = reader.readLine();
            } finally {
                reader.close();
            }

            final String PROC_VERSION_REGEX =
                "\\w+\\s+" + /* ignore: Linux */
                "\\w+\\s+" + /* ignore: version */
                "([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */
                "\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx@xxxxx.constant) */
                "\\((?:[^(]*\\([^)]*\\))?[^)]*\\)\\s+" + /* ignore: (gcc ..) */
                "([^\\s]+)\\s+" + /* group 3: #26 */
                "(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */
                "(.+)"; /* group 4: date */

            Pattern p = Pattern.compile(PROC_VERSION_REGEX);
            Matcher m = p.matcher(procVersionStr);

            if (!m.matches()) {
            	if (aDebug.ENABLED)
            		aDebug.d(LOG_TAG, "Regex did not match on /proc/version: " + procVersionStr);
                return CONSTS.UNAVAILABLE;
            } else if (m.groupCount() < 4) {
            	if (aDebug.ENABLED)
            		aDebug.d(LOG_TAG, "Regex match on /proc/version only returned " + 
            		                  m.groupCount() + " groups");
                return CONSTS.UNAVAILABLE;
            } else {
                /*return (new StringBuilder(m.group(1)).append("\n").append(
                        m.group(2)).append(" ").append(m.group(3)).append("\n")
                        .append(m.group(4))).toString();*/
                return m.group(1);
            }
        } catch (IOException e) {
        	if (aDebug.ENABLED)
        		aDebug.e(LOG_TAG, 
        		         "IO Exception when getting kernel version for Device Info screen",
        		         e);

            return CONSTS.UNAVAILABLE;
        }
    }
	
	static boolean
    IsRootDevice()
    {
        try {
            String[] strPaths = new String[] {"/system/bin/su", "/system/xbin/su",
                                              "/sbin/su", "/data/local/xbin/su",
                                              "/data/local/bin/su", "/system/sd/xbin/su",
                                              "/system/bin/failsafe/su", "/data/local/su"};
            for (String strPath: strPaths) {
                File su = new File(strPath);
                if (su.exists()) return true;
            }
        } catch (Exception e) {}
        return false;
    } 
}
